Software submitted for execution on a given computing device may take the form of interpreted code, executable code, or a mixture of the two. Executable code is lower-level, in the sense that it includes processor architecture details such as register names and hard-coded register offsets. Executable code is typically generated from source code by a compiler. Source code resembles a natural language (e.g., English) but has strict syntactic and semantic limitations not present in natural languages. Even so, source code is often written in a programming language that is processor-architecture-agnostic, so it lacks many details found in executable code. Interpreted code can be written as source code, in a scripting language or other programming language. An interpreter may parse source code and perform the corresponding behavior directly, may translate source code into an intermediate representation which is then immediately executed, and/or may match the source code to pieces of precompiled code which are then executed.
Debugging executable code can be very challenging when the corresponding source code is not available, or when a source-level debugger that maps executable code to source code is either unavailable or ineffective. In addition to containing many processor-specific details not found in corresponding source code, in executable code symbolic names defined in source code have been translated into low-level storage identifiers such as registers and register-based memory accesses. Moreover, executable code is often tailored to a system architecture and/or optimized in ways that obscure the correspondence between source code and a given executable code instruction.